﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.ComponentModel;
using ProgNetComponents.Utils.EventHandlers;
using System.Collections.ObjectModel;

namespace ProgNetComponents.Validation.Rules
{
    /// <summary>
    /// Base validation rule
    /// </summary>
    [System.ComponentModel.DesignTimeVisible(false)]
    public abstract class ValidationRule : ProgNetComponents.Controls.BaseCustomComponent
    {
        /// <summary>
        /// Occurs when [validation failed].
        /// </summary>
        public event DataRowEventHandler ValidationFailed;
        /// <summary>
        /// Occurs when [validation passed].
        /// </summary>
        public event DataRowEventHandler ValidationPassed;

        /// <summary>
        /// Initializes a new instance of the <see cref="ValidationRule"/> class.
        /// </summary>
        protected ValidationRule()
        {

        }

        /// <summary>
        /// Validates the row.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns></returns>
        public virtual bool ValidateRow(DataRow row)
        {
            if (SkipValidation)
                return true;
            if (SkipIfRowNotModified && row.RowState == DataRowState.Unchanged)
                return true;
            bool result = true;
            result = DoValidate(row);

            if (result)
            {
                OnValidationPassed(row);
                FireValidationPassed(row);
            }
            else
            {
                OnValidationFailed(row);
                FireValidationFailed(row);
            }
            return result;
        }

        /// <summary>
        /// Gets or sets if this rule should be skipped. ValidateRow will return true if this is set.
        /// </summary>
        /// <value>
        ///   <c>true</c> if [skip validation]; otherwise, <c>false</c>.
        /// </value>
        [DefaultValue(false)]
        public bool SkipValidation
        {
            get;
            set;
        }

        /// <summary>
        /// If true row will be validated only of it is added or modified
        /// </summary>
        /// <value>
        /// <c>true</c> if [skip if row not modified]; otherwise, <c>false</c>.
        /// </value>
        [DefaultValue(true)]
        public bool SkipIfRowNotModified
        {
            get;
            set;
        }

        /// <summary>
        /// Does the validate.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns></returns>
        protected abstract bool DoValidate(DataRow row);

        /// <summary>
        /// Fires the validation passed.
        /// </summary>
        /// <param name="row">The row.</param>
        protected void FireValidationPassed(DataRow row)
        {
            if (ValidationPassed != null)
                ValidationPassed(this, new DataRowEventArgs(row));
        }
        /// <summary>
        /// Fires the validation failed.
        /// </summary>
        /// <param name="row">The row.</param>
        protected void FireValidationFailed(DataRow row)
        {
            if (ValidationFailed != null)
                ValidationFailed(this, new DataRowEventArgs(row));
        }
        /// <summary>
        /// Called when [validation passed].
        /// </summary>
        /// <param name="row">The row.</param>
        protected virtual void OnValidationPassed(DataRow row)
        {

        }
        /// <summary>
        /// Called when [validation failed].
        /// </summary>
        /// <param name="row">The row.</param>
        protected virtual void OnValidationFailed(DataRow row)
        {

        }

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            if(Site!=null)
                return Site.Name;
            return GetType().Name;
        }

        /// <summary>
        /// Clears the validation settings.
        /// </summary>
        public virtual void ClearValidationSettings()
        {

        }
    }

    /// <summary>
    /// Collection of ValidationRule
    /// </summary>
    public class ValidationRuleCollection : ObservableCollection<ValidationRule> 
    {
        /// <summary>
        /// Adds all rules to collection.
        /// </summary>
        /// <param name="rules">The rules.</param>
        public void AddRange(IEnumerable<ValidationRule> rules)
        {
            if (rules != null)
            {
                foreach (var rule in rules)
                {
                    Add(rule);
                }
            }
        }
        /// <summary>
        /// Clears the validation settings for all rules.
        /// </summary>
        public void ClearValidationSettings()
        {
            foreach (var r in this)
                r.ClearValidationSettings();
        }
    }
}